package com.raymond.utils;


import lombok.extern.slf4j.Slf4j;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.util.HashMap;
import java.util.Map;


/**
 * XML工具类
 *
 * @author :  raymond
 * @version :  V1.0
 * @date :  2019-11-26 11:18
 */
@Slf4j
public class XmlUtil {
    /**
     * 解决性能问题，将获取转换类存放在缓存中
     */
    private static Map<String, JAXBContext> jaxbContextMap = new HashMap<>();

    /**
     * 获取JAXBContext对象
     * @param clazz 转换的对象
     * @return JAXBContext对象
     * @throws JAXBException 异常
     */
    private static JAXBContext getJaxbContext(Class clazz) throws JAXBException {
        // 利用jdk中自带的转换类实现
        JAXBContext jaxbContext = jaxbContextMap.get(clazz.getName());

        if(jaxbContext == null){
            // 如果每次都调用JAXBContext.newInstance方法，会导致性能急剧下降
            jaxbContext = JAXBContext.newInstance(clazz);
            jaxbContextMap.put(clazz.getName(), jaxbContext);
        }
        return jaxbContext;
    }
    /**
     * 将对象直接转换成String类型的 XML输出
     *
     * @param obj 对象
     * @return xml字符串
     */
    public static String convertToXml(Object obj) {
        // 创建输出流
        StringWriter sw = new StringWriter();
        try {

            JAXBContext context = getJaxbContext(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            log.error("将对象直接转换成String类型的 XML输出异常", e);
        }
        return sw.toString();
    }

    /**
     * 将对象根据路径转换成xml文件
     *
     * @param obj 对象
     * @param path 路径
     */
    public static void convertToXml(Object obj, String path) {
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = getJaxbContext(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            // 创建输出流
            FileWriter fw = null;
            try {
                fw = new FileWriter(path);
            } catch (IOException e) {
                log.error("IO异常", e);
            }
            marshaller.marshal(obj, fw);
        } catch (JAXBException e) {
            log.error("将对象根据路径转换成xml文件异常", e);
        }
    }


    /**
     * 将String类型的xml转换成对象
     * @param clazz 需要转换的类
     * @param xmlStr 需要转换的内容
     * @return 转换结果集
     */
    public static <T> T convertXmlStrToObject(Class<T> clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = getJaxbContext(clazz);
            // 进行将Xml转成对象的核心接口
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            log.error("将String类型的xml转换成对象异常", e);
        }
        return (T) xmlObject;
    }


    /**
     * 将file类型的xml转换成对象
     * @param clazz 需要转换的类
     * @param xmlPath 文件路径
     * @return 转换结果集
     */
    public static <T> T convertXmlFileToObject(Class<T> clazz, String xmlPath) {
        Object xmlObject = null;
        try {
            JAXBContext context = getJaxbContext(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            FileReader fr = null;
            try {
                fr = new FileReader(xmlPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            xmlObject = unmarshaller.unmarshal(fr);
        } catch (JAXBException e) {
            log.error(" 将file类型的xml转换成对象异常", e);
        }
        return (T)xmlObject;
    }

}
